package com.gitee.wsl.mathematics.geometry.d2.contour.ext

import com.gitee.wsl.mathematics.geometry.d2.contour.ShapeContour
import com.gitee.wsl.mathematics.geometry.d2.contour.contour
import com.gitee.wsl.mathematics.vector.ext.distanceTo


fun ShapeContour.removeLoops(attempts: Int = 0): ShapeContour {
    if (attempts > 10) {
        error("tried more than 10 times to remove loops")
    }

    if (this.closed) {
        return this
    } else {
        val selfIntersections = intersections(this, this)
        if (selfIntersections.isEmpty()) {
            return this
        } else {

            val toFix = selfIntersections.minByOrNull { it.a.contourT }!!
            val sorted = listOf(toFix.a.contourT, toFix.b.contourT).sorted()

            val head = this.sub(0.0, sorted[0])
            val tail = this.sub(sorted[1], 1.0)
            val tailSegments = tail.segments.toMutableList()


            if (head.segments.isEmpty()) {
                return tail
            }
            if (tail.segments.isEmpty()) {
                return head
            }

            tailSegments[0] = tailSegments.first().copy(start = head.segments.last().end)
            val fixedTail = ShapeContour(tailSegments, closed = false)
            return (head.removeLoops(attempts+1) + fixedTail.removeLoops(attempts+1))
        }
    }
}




/**
 * Create a contour from a list of contours
 */
fun ShapeContour.Companion.fromContours(contours: List<ShapeContour>, closed: Boolean, connectEpsilon:Double=1E-6) : ShapeContour {
    @Suppress("NAME_SHADOWING") val contours = contours.filter { !it.empty }
    if (contours.isEmpty()) {
        return EMPTY
    }
    return contour {
        moveTo(contours.first().position(0.0f))
        for (c in contours.windowed(2,1,true)) {
            copy(c[0])
            if (c.size == 2) {
                val d = c[0].position(1.0f).distanceTo(c[1].position(0.0f))
                if (d > connectEpsilon ) {
                    lineTo(c[1].position(0.0f))
                }
            }
        }
        if (closed) {
            close()
        }
    }
}